#include "songitem.h"
#include "infodownloader.h"
#include "blur.h"
#include "lyricstext.h"
#include <QPainter>
#include <QDateTime>
#include <QTimeLine>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QDesktopServices>
#include <QGraphicsScene>
#include <QPalette>
#include <QProcess>
#include <QUrl>
#include <QCursor>
#include <QGraphicsView>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>

SongItem::SongItem(QString artist, QString title) : yRotation(0) {
	lyricsText = new LyricsText(this);
	lyricsText->setTransform(QTransform().rotate(180, Qt::YAxis));
	lyricsText->hide();

	songInfo.title = title;
	songInfo.artist = artist;
	resize(QSize(100,50));
	qsrand(QDateTime::currentDateTime().toTime_t());
	fillColor = QColor::fromHsv(qrand()%360, 200, 200, 128);
	infoDownloader = new InfoDownloader(this);
	connect(infoDownloader, SIGNAL(songInfoReady()), this, SLOT(onSongInfoReady()));
	connect(infoDownloader, SIGNAL(coverImageReady(QPixmap)), this, SLOT(onCoverImageReady(QPixmap)));
	connect(infoDownloader, SIGNAL(lyricsReady(QString)), this, SLOT(onLyricsReady(QString)));
	infoDownloader->startFetchingSongInfo();
	trackIcon.load(":/images/track22.png");
	artistIcon.load(":/images/artist22.png");
	albumIcon.load(":/images/album22.png");
	setOpacity(0.6);
	setAcceptHoverEvents(true);
	textFont.setPointSize(qMax(20, QFont().pointSize()));
}

void SongItem::useBaseColor(bool alternate) {
	fillColor = scene()->palette().color(alternate ? QPalette::AlternateBase : QPalette::Base);
}

void SongItem::onSongInfoReady() {
	songInfo = infoDownloader->getSongInfo();
	setToolTip("Open page for "+songInfo.title);
	setCursor(Qt::PointingHandCursor);
	update();
}

void SongItem::onLyricsReady(QString lyrics) {
	songInfo.lyrics = lyrics;
	lyricsText->setText(songInfo.lyrics);
	animateSizeTo(QSize(rect.width(), lyricsText->boundingRect().height()+20));
}

QVariant SongItem::itemChange(GraphicsItemChange change, const QVariant & value) {
	if(change == ItemPositionHasChanged && scene())
		emit(geometryChanged(QRectF(scenePos(), rect.size())));
	return QGraphicsItem::itemChange(change, value);
}

void SongItem::onCoverImageReady(QPixmap coverImage) {
	// small images are errors
	if(coverImage.width() > 10 && coverImage.height() > 10) {
		// render the shadow on the full image
		int radius = 4;
		int shadowOffset = 3;
		int buffer = qMax(radius, shadowOffset);
		QImage shadow(coverImage.width()+buffer*2, coverImage.height()+buffer*2, QImage::Format_ARGB32);
		shadow.fill(Qt::transparent);
		QPainter px(&shadow);
		px.setBrush(Qt::black);
		px.drawRect(shadowOffset, shadowOffset, coverImage.width(), coverImage.height());
		px.end();
		// TODO: use QPixmapDropShadowFilter instead of the expblur when Qt 4.6 is released
		expblur<16,7>(shadow, radius);
		px.begin(&shadow);
		px.drawPixmap(QPoint(0, 0), coverImage);
		px.end();
		shadowCover = shadowCover.fromImage(shadow);
	}
	else
		shadowCover = QPixmap(":/images/media-optical-audio.png");
	updateCover();
	update();
}


void SongItem::resize(QSize size) {
	prepareGeometryChange();
	lyricsText->setPos(size.width()-10, 10);
	lyricsText->resize(QSizeF(size.width()-20, size.height()-20));
	rect = QRectF(QPoint(0,0), size);
	if(transform().isIdentity())
		emit(geometryChanged(QRectF(scenePos(), size)));
	updateCover();
	update();
}

void SongItem::onNextSongMoved(const QRectF geometry) {
	double newHeight = qMax(50.0, (scenePos().y()+rect.height())-geometry.bottom());
	newHeight = newHeight < rect.height() ? newHeight : rect.height();
	resize(QSize(geometry.width(), newHeight));
	setPos(geometry.left(), geometry.bottom());
}

void SongItem::updateCover(){
	if(!shadowCover.isNull()) {
		double maxWidth = rect.width()/3;
		double maxHeight = rect.height()-4;
		// if the whole image doesn't fit, scale it down to fit
		if(shadowCover.width() > maxWidth || shadowCover.height() > maxHeight)
			renderedCover = shadowCover.scaled(QSize(maxWidth, maxHeight), Qt::KeepAspectRatio);
		else  // otherwise render the shadow on the full image
			renderedCover = shadowCover;
	}
}

void SongItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) {
	painter->setBrush(fillColor);
	painter->drawRect(rect);
	if(getYRotation() <= 90) {
		QFontMetrics fm(textFont);
		int fontHeight = qMax(artistIcon.height(), fm.height())+5;
		int heightDiff = rect.height()-(fontHeight*3);
		if(heightDiff > 0) {
			painter->setOpacity(0.8);
			int yPos = rect.top()+heightDiff/2;
			int xPos = rect.left()+rect.width()/3;
			int iconWidth = artistIcon.width()+5;
			painter->drawPixmap(xPos, yPos, artistIcon);
			painter->drawPixmap(xPos, yPos+fontHeight, trackIcon);
			if(!songInfo.album.isEmpty())
				painter->drawPixmap(xPos, yPos+2*fontHeight+3, albumIcon); // hack, the album icon looks top heavy, so we shift it a bit
			xPos += iconWidth;
			painter->setFont(textFont);
			painter->drawText(QRectF(xPos, yPos, 2*rect.width()/3-iconWidth, fontHeight), Qt::AlignLeft, songInfo.artist);
			painter->drawText(QRectF(xPos, yPos+fontHeight, 2*rect.width()/3-iconWidth, fontHeight), Qt::AlignLeft, songInfo.title);
			painter->drawText(QRectF(xPos, yPos+2*fontHeight, 2*rect.width()/3-iconWidth, fontHeight), Qt::AlignLeft, songInfo.album);

			if(!renderedCover.isNull()) {
				int xoffset = (rect.width()/3-qMin(qRound(rect.width()/3), renderedCover.width()))/2;
				int yoffset = (rect.height()-qMin(qRound(rect.height()), renderedCover.height()))/2;
				painter->drawPixmap(rect.topLeft()+QPointF(xoffset, yoffset), renderedCover);
			}
		}
		else {
			if(!renderedCover.isNull())
				painter->drawPixmap(rect.topLeft()+QPointF(2, 2), renderedCover);
			QFont smallerFont = textFont;
			smallerFont.setPointSize(smallerFont.pointSize()*0.75);
			painter->setFont(smallerFont);
			painter->drawText(QRectF(renderedCover.width()+5, 0, rect.width()-2*renderedCover.width()-10, rect.height()), Qt::AlignCenter | Qt::TextWordWrap, songInfo.artist+" - "+songInfo.title);
		}
	}
}

void SongItem::mousePressEvent(QGraphicsSceneMouseEvent* event) {
	if(event->button() == Qt::LeftButton) {
		if(songInfo.songId) {
			QString address = QString("http://www.radioparadise.com/content.php?name=songinfo&song_id=")+QString::number(songInfo.songId);
			QDesktopServices::openUrl(QUrl(address));
		}
	}
	else if(event->button() == Qt::RightButton) {
		infoDownloader->startFetchingLyrics();
		toggleLyrics();
	}
}

void SongItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event) {
	qDebug() << "hover enter";
	setupFadeTo(1.0);
	QGraphicsItem::hoverEnterEvent(event);
}


void SongItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) {
	setupFadeTo(0.6);
	QGraphicsItem::hoverLeaveEvent(event);
}

void SongItem::animateSizeTo(QSize newSize) {
	QPropertyAnimation *a = new QPropertyAnimation((QObject*)this, "size");
	a->setStartValue(getSize());
	a->setEndValue(QVariant(newSize));
	a->setDuration(750);
	a->setEasingCurve(QEasingCurve::InOutQuad);
	a->start(QAbstractAnimation::DeleteWhenStopped);
}

void SongItem::setupFadeTo(float o) {
	QPropertyAnimation *a = new QPropertyAnimation((QObject*)this, "opacity");
	a->setStartValue(opacity());
	a->setEndValue(QVariant(o));
	a->setDuration(400);
	a->setEasingCurve(QEasingCurve::Linear);
	a->start(QAbstractAnimation::DeleteWhenStopped);
}

void SongItem::toggleLyrics() {
	QPropertyAnimation *a = new QPropertyAnimation((QObject*)this, "yrotation");
	a->setStartValue(yRotation);
	a->setDuration(500);
	a->setEasingCurve(QEasingCurve::InQuad);
	a->setEndValue(90);
	connect(a, SIGNAL(finished()), this, SLOT(onFlipHalfway()));
	QPropertyAnimation *b = new QPropertyAnimation((QObject*)this, "yrotation");
	b->setStartValue(90);
	b->setDuration(500);
	b->setEasingCurve(QEasingCurve::OutQuad);
	b->setEndValue(yRotation ? 0 : 180);
	QSequentialAnimationGroup* ag = new QSequentialAnimationGroup(this);
	ag->addAnimation(a);
	ag->addAnimation(b);
	ag->start(QAbstractAnimation::DeleteWhenStopped);
}

void SongItem::onFlipHalfway() {
	lyricsText->setVisible(!lyricsText->isVisible());
}

void SongItem::setYRotation(qreal yrot) {
	yRotation = yrot;
	QTransform trans;
	trans.translate(rect.width()/2, rect.height()/2);
	trans.rotate(yrot, Qt::YAxis);
	trans.translate(-rect.width()/2, -rect.height()/2);
	setTransform(trans);
}
